Range and endurance have been mentioned in the preceding sections - and we have introduced that for maximum range the pilot should fly at \(V_{md}\), whilst to fly for maximum endurance the pilot should fly at \(V_{mp}\).
However - the above speeds are valid only for unpowered flight. So these speeds are suitable for a glider, but once an engine is introduced to an aircraft, these speeds no longer give the maximum range or the maximum endurance.
Furthermore, the propulsor type changes the speeds for both. In the following section, the best range and endurance speeds for jet and propeller-driven aircraft will be explored.
Range and Endurance¶
Range and endurance are intuitive concepts:
Range (\(R\)): The maximum horizontal distance that an aircraft can cover.
Endurance (\(E\)): The time an aircraft can remain in flight
In the following analysis, the range and endurance for certain fuel quantities will be determined. For (hopefully) obvious reasons, some further definitions of range will help us here
Range subdefinitions¶
Safe Range: The maximum distance between two airfields, for which an aircraft can fly a safe a reliable mission with a given payload.
This is an involved calculation involving take-off/landing/weather/diversion allowances etc. - there isn’t an easy means to do this calculation, so tends to be performed computationally.
For aircraft performance there are some more simple definitions of range:
Still Air Range (SAR): The maximum distance possible if an aircraft takes off, climbs to cruise altitude, and then cruises until all fuel is expended.
Obviously not desirable to run out of fuel at altitude, but SAR gives a good indication of the influence of aircraft parameters on range.
Gross Still Air Range (GSAR): The maximum distance possible if an aircraft commences cruise at altitude and continues until all fuel is expended.
The relationship between SAR and GSAR tends to be easy to define.
GSAR much easier to calculate
What will be covered here
Defining the problem¶
To calculate GSAR, you might think that we need to:
find out the fuel flow rate, \(\dot{m}_{fuel}\) for thrust/power associated with \(V_{md}\)
get the endurance from the fuel mass, \(m_{fuel}\) divided by the flow rate \(E=\frac{m_{fuel}}{\dot{m}_{fuel}}\)
hence \(R=E\cdot V_{md}\)
The above reasoning is effectively how range is determined, but there are some complications that you may/may not be considering:
Aircraft take-off with a lot of fuel, so the aircraft weight changes with time and accordingly so do almost all the parameters we have considered up to this point
This means that some trade-offs have to be made in efficiency to allow a reasonable cruise - and we will see these
Breguet Range Equation¶
The Breguet Range Equation (BRE) is named after a French aircraft designer, but was actually derived in the 1920’s by J G Coffin.
History and namesakes…
I’ve loosely read the history of the BRE and it being Coffin who actually came up with it in NACA Report 1969, but I’ve never actually delved into the legacy of this equation. If you wish to, and suggest a correct here, feel free.
The BRE allows a simple means to calculate GSAR, and can be defined in words as:
The BRE was first implemented for propeller aircraft, and is derived differently for thrust and power engines. In the following it will be derived separately for the two engines types.
Engine fuel burn¶
To calculate the engine fuel burn of both types of engine, two new parameters are introduced
A parameter, \(c_t\), is introduced which is:
Thrust Specific Fuel Consumption (TSFC) for a turbojet \(c_t\) - mass of fuel burned per unit of thrust per second
Specific Fuel Consumption (SFC) for a turboprop \(c\) - mass of fuel burned per unit of power per second
Thrust specific fuel consumption - units¶
In the above, the SI units are \(\left\{c_t\right\}=\left\{\frac{kg}{N\cdot s}\right\}\) which has dimensions of \(\left[\frac{\text{L}}{\text{T}}\right]\). You might see this expressed as \(\frac{g}{kN\,s}\), which is actually the same units.
In US customary units, this is \(\left\{c_t\right\}=\left\{\frac{lb}{lbf\cdot s}\right\}\).
You may see some slightly different units such as \(\left[\frac{kg}{kN\cdot hr}\right]\) so be sure to convert to SI or US customary base units
Specific fuel consumption - units¶
In the above, the SI units are \(\left\{c\right\}=\left\{\frac{kg}{W\cdot s}\right\}\) which has dimensions of \(\left[\frac{\text{T}^2}{\text{L}^2}\right]\). You might see this expressed as \(\frac{g}{kW\,s}\), which is actually the same units.
In US customary units, this is \(\left\{c_t\right\}=\left\{\frac{lb}{hp\cdot s}\right\}\).
You may see some slightly different units such as \(\left[\frac{kg}{kW\cdot hr}\right]\) so be sure to convert to SI or US customary base units
The analysis is slightly different for jet and propeller-driven aircraft, so jet aircraft will be explored first.
BRE - Jet Aircraft¶
The fundamental concept is, again:
So for a jet aircraft this is
which can be rearranged for the time
since the endurance/range is defined by cruise conditions, the equilibrium steady flight conditions of \(T=D\) and \(L=W\) can be utilised such that
which can be substituted into the BRE to give
for constant lift-to-drag ratio and TSFC, the equation above can be integrated with the limits \(t_{0}\) and \(t_{1}\) corresponding to \(W_{0}\) and \(W_{1}\) where 0 denotes the start of cruise, and 1 denotes the end.
This yields the endurance, \(E\):
Jet Aircraft: Maximum Endurance¶
For a given \(c_t\), \(W_0\), and \(W_{1}\), Equation (7) shows that the best endurance for a jet aircraft is found at the minimum drag speed. If you’re unsure why it shows this - look at the equation and consider what can be maximised.
To find the range, the equation above needs to be modified - the range is given by the following if it is assumed TAS remains constant.
Jet Aircraft: Range¶
If constant true airspeed is assumed, then the range is given by the endurance multiplied by the range
or
The Range Function¶
The equation above gives the design/mission choices that help maximise range:
In the Breguet Range Equation, Equation BRE, some parameters are dictated by the problem:
\(W_{1}\) is the weight of the aircraft including fuel
\(W_{0}\) is the weight of the aircraft with no fuel, or with a certain mandated reserve
\(c_t\) is the TSFC and will generally be given in a problem
Other parameters are unknown - so the range function needs to be constrained (written in terms of other parameters) in order to use Equation BRE to determine the possible range. This will yield the speed for best range, and hence also enable determination of the flight duration.
The ‘range function’ is the expression \(V\frac{C_L}{C_D}\) and clearly maximum range is given by the maximum value thereof.
In practice, this means replacing \(V\frac{C_L}{C_D}\) with an equivalent expression representing the variation of the parameters therein, by finding another means of representing \(V\) as a function of \(C_L\) or \(C_D\).
Different means of doing this will be explored - first the theory will be explained, and then numerical examples will follow.
Best Jet Range¶
To find the best range, the aircraft speed equation, Eq (5) can be used to substitute \(V\) for aerodynamic and inertial parameters:
which has \(W\) in it, so this needs to be substituted before the integration over \(W\). Defining the incremental distance covered, \(dS\) as \(dS=dE\cdot V\):
The range, \(R\), is the integration of the equation above
which yields
Looking at (9), the choice that can be made to maximise range can be determined:
We can see that for a jet aircraft, the range is a function of the starting altitude. That is, start a cruise high to fly far.
Of the other choices above, the one that is of interest to us is the aerodynamic consideration - maximise \(\frac{C_L^{1/2}}{C_D}\). You should be able to easily show that this is achieved by a value of \(C_L\)
Which is found at the flightspeed
So the speed for best range in a jet aicraft is
Which is an interesting result - since it is the product of \(V\) and \(\frac{C_L}{C_D}\) that needs to be maximum, this is achieved at a speed above \(V_{md}\) and hence at a lower value of \(\frac{C_L}{C_D}\).
So to go far in a jet aircraft, the speed above gives a lower endurance but but the faster TAS allows more ground to be covered than for the best endurance speed, \(V_{md}\).
Numerical Example¶
About units
You (that’s you, IIT student) should be able to do these calculations both in SI units and US customary units. Since I got my degree and PhD outside of America, I have an appreciation (to use the term loosely) for US customary units, but my actual application has always been to convert to SI at the start, and then convert the answer back to US customary units if I need to provide one.
For this reason, I work in SI in written examples for class but I will provide examples with US customary units used throughout. I simply don’t want to make a mistake when going through work in class, and end up a factor of 32 out, or have mixed up lb for lbf or whatever else I could have done.
I managed to find this whilst googling about the US and the metric system, if you want some further reading. https://www.nist.gov/system/files/documents/pml/wmd/metric/1136a.pdf
This is an adaptation of Example 5.19 in Anderson[And99] - I claim no originality or authorship for the data provided, but I’ve used it to confirm my US customary calculation is correct before adapting.
Question:
Estimate the maximum range at altitudes of 20,000, 30,000, and 40,000 feet for the Gulfstream IV given the following:
Mass of aircraft without fuel: 43,500lb. Mass of usable fuel: 29,500lb. Drag model: \(C_D=0.015 + 0.08\cdot C_L^2\) Wing area: 950 square feet TSFC: 0.69 lb of fuel consumed per pound of thrust per hour.
import numpy as np
from ambiance import Atmosphere
h1 = 20000
h2 = 30000
h3 = 40000
m_1 = 43500 # mass in lbs of aircraft without fuel
m_fuel = 29500 # mass in lbs of fuel
# # Unit conversions
lb_to_kilo = 0.453592
pound_to_newton = 4.44822
hour_to_second = 3600
ft_to_metre = 0.3048
metre_to_miles = 0.000621371
km_to_miles = 0.621371
g = 9.80665 # Gravitational acceleration
kg_to_slugs = 0.0685218
miles_to_feet = 5280 # Because everyone recalls this number...
# The start weight of the aircraft is equal to the end weight plus the fuel weight
m_0 = m_1 + m_fuel
# Aircraft drag model - from Anderson
CD0 = 0.015
K = 0.08
S = 950 # In square feet
# Thrust specific fuel consumption
c_t = 0.69 # c_t in lb of fuel per pound of thrust per hour
# Convert c_t to consistent units (lb of fuel per pound of thrust per second, not per hour)
c_t = c_t / 3600
# Find the Cl and Cd for max range
Cl = np.sqrt(CD0/3/K)
Cd = CD0 + K * Cl**2
# Iterate over the altitudes
for h_ft in [h1, h2, h3]:
############################################################################
################### First do the calculation in US customary units
############################################################################
# Get density for this altitude - this will be in SI
h = h_ft * ft_to_metre
Atmopshere_for_30k = Atmosphere(h)
rho_SI = Atmopshere_for_30k.density[0]
print(f"For an altitude of {h_ft:1.0f}ft/{h/1e3:1.1f}km")
# Convert to US customary density units of slugs per cubic feet
rho_US = rho_SI * kg_to_slugs * ft_to_metre**3 # i.e., dividing be the reciprocal of ft_to_metre**3
# Now get range - which will be in feet (US Customary base units), so convert to miles for readability
## Note that since c_t has been defined as a mass, and so has the aircraft mass - we can avoid using "g" by
# keeping the aircraft mass as mass since "g" is in the denominator of the BRE
# If you don't want to do this you can save g in US customary as 32.17405ft/s^2, but the pounds/pounds/poundal
# conversion can be a real pain
R = 2/c_t * np.sqrt(2/rho_US/S) * Cl**.5 / Cd * (m_0**.5 - m_1**.5) / miles_to_feet
print(f"The range is {R:1.0f} miles")
############################################################################
################### Now in SI units
############################################################################
# Do the conversion into SI units
c_t = c_t * lb_to_kilo * g / pound_to_newton
# Find the Cl and Cd for best range
Cl = np.sqrt(CD0/3/K)
Cd = CD0 + K * Cl**2
# wing area
S_SI = S * ft_to_metre**2
# Convert units
w_0 = m_0 * lb_to_kilo * g
w_1 = m_1 * lb_to_kilo * g
# Determine range in km
R = 2/c_t * np.sqrt(2/rho_SI/S_SI) * Cl**.5 / Cd * (w_0**.5 - w_1**.5) / 1e3
print(f"The range is {R:1.0f}km which is equal to {R*km_to_miles:1.0f} miles")
print(" ")
For an altitude of 20000ft/6.1km
The range is 3924 miles
The range is 6315km which is equal to 3924 miles
For an altitude of 30000ft/9.1km
The range is 4681 miles
The range is 7533km which is equal to 4681 miles
For an altitude of 40000ft/12.2km
The range is 5764 miles
The range is 9276km which is equal to 5764 miles
Most Efficient - Cruise Climb¶
The most aerodynamically efficient cruise would be with constant best \(C_L/C_D\), and constant \(f\). These have some implications. Have a look at these in the dropdown below:
Implication of the most efficient cruise
Above, it was stipulated that the lift-to-drag ratio (\(C_L/C_D\)), TSFC \(f\), and \(V_{T}\) were constant. These assumptions have some implications:
Fuel burn causes a reduction in aircraft weight - so as \(W\) drops, the dimensional value of lift, \(L\), must also drop (\(L=W\))
Since TAS is constant, for \(L\) to drop, either \(C_L\) must drop or \(\sigma\) must reduce
But it was also assumed that the aircraft flies at the best aerodynamic efficiency, and that \(C_L/C_D\) was constant, which implies a constant angle of attack
Therefore, \(\sigma\) must reduce, and hence altitude must increase for an efficient cruise
As \(C_L\) reduces, for constant \(C_L/C_D\), \(C_D\) must reduce in proportion to \(\sigma\) also
Since \(T=D\), the thrust must reduce with altitude
For constant TSFC, \(f\), the throttle setting must be constant
Hence thrust must be modelled from \(T=T_{SL}\cdot\sigma^n\) with \(n=1\)
As discussed previously, \(n\) is dependent on altitude and engine type - and the thrust model above is a vast simplification anyway
\(n=1\) is more suitable in the stratosphere (above 11km-ish), where the temperature falls with altitude (slightly more complicated than this, but it works enough for us).
Below 11km, in the troposphere, the temperature falls with altitude - and hence \(n<1\), so thrust falls less rapidly with altitude. To maintain constant \(C_L/C_D\) requires the pilot to reduce the throttle to maintain \(V\) or \(C_L\), which would change the TSFC
The derivation has arrived at the so-called cruise-climb case, whereby the aircraft altitude rises along the cruise to maintain peak aerodynamic efficiency. This is infrequently allowed by air traffic control - but aircraft often follow a stepped-climb, which is a planned series of altitude changes to allow some of the benefits.
Further to the above, two cruise-climb cases can be explored:
Throttle Restricted - The throttle setting is fixed, and the aircraft must vary altitude to maintain constant \(C_L/C_D\)
Throttle Unrestricted - The throttle can be altered to maintain constant \(C_L/C_D\)
Constant Altitude Cruise¶
Instead of cruise-climb, a constant altitude cruise allows the velocity to vary - the range will obviously be different.
Starting again with the the differential range expression where \(dS\) is the differential displacement:
Since \(\sigma\) is held constant, the aircraft speed equation can be substituted in the above
Note that for the maximum range, \(\frac{C_L^{1/2}}{C_D}\) must be maximised - which is the same as for the thrust unrestricted cruise-climb case.
For this case, altitude and \(C_L\) are held constant. As \(W\) reduces, \(L\) reduces, so \(V\) must reduce. Hence the range must be less as the aircraft is flying slower from \(t>0\).
Since \(C_D\) is constant, \(D\) and hence \(T\) must reduce - so throttle must be reduced and a variation in the fuel consumption will occur.
For this case, an average value of \(f\) must be used, or treat as a series of shorter steps and integrate numerically.
Actual Cruise¶
A third, and much more common cruise profile is to cruise at a constant altitude, at a constant \(V\). Hence to reduce \(L\) to match the reduction in weight, \(\alpha\) must be reduced, changing \(C_L/C_D\). This is a more complex analysis and beyond the scope of this course.
Cruise Comparisons¶
For an aircraft with the following parameters:
\(W_S\) |
100kN |
\(W_F\) |
60kN |
\(S\) |
50m\(^2\) |
\(C_{D0}\) |
0.02 |
\(K\) |
0.05 |
\(T_{SL}\) |
20kN |
\(f\) |
0.0001kg/Ns |
For a cruise starting at 12km altitude, the three different cruise ranges can be calculated
The code below calculates the different cruise-climb cases - note that these calculations could easily be performed by hand.
import numpy as np
from myst_nb import glue
from ambiance import Atmosphere
# Aircraft parameters
Ws = 100*1e3
We = 60*1e3
S = 50
CD0 = 0.02
K = 0.05
T_sl = 20*1e3
f = 0.0001
alt = 12 # altitude in km
g = 9.80665 # Gravitational acceleration
rho_sl = 1.225
############################################
## Thrust restricted cruise-climb parameters
############################################
CL_trcc = np.sqrt(CD0/2/K)
CD_trcc = 3/2 * CD0
range_function_trcc = np.sqrt(2 * T_sl / rho_sl / S) * CL_trcc / CD_trcc ** (3/2)
range_trcc = 1 / f / g * range_function_trcc * np.log(Ws/We)
# Save these values
glue("CD_trcc", CD_trcc, display=False);
glue("CL_trcc", CL_trcc, display=False);
glue("range_function_trcc", range_function_trcc, display=False);
glue("range_trcc", range_trcc/1e3, display=False);
############################################
## Thrust unrestricted cruise-climb parameters
############################################
mosphere = Atmosphere(alt*1000)
rho = mosphere.density[0]
sig_1 = rho/rho_sl
CL_tucc = np.sqrt(CD0/3/K)
CD_tucc = 4/3 * CD0
range_function_tucc = np.sqrt(Ws / (0.5 * sig_1 * rho_sl * S)) * CL_tucc ** .5 / CD_tucc
range_tucc = 1 / f / g * range_function_tucc * np.log(Ws/We)
# Save these values
glue("CD_tucc", CD_tucc, display=False);
glue("CL_tucc", CL_tucc, display=False);
glue("range_function_tucc", range_function_tucc, display=False);
glue("range_tucc", range_tucc/1e3, display=False);
Thrust Restricted¶
Using the expressions derived above, the lift coefficient for Thrust restricted cruise climb is 0.447, and the drag coefficient is 0.030. This gives the range function as 2199.430 which yields a range of 1146km
Thrust Unrestricted¶
Using the expressions derived above, the lift coefficient for Thrust unrestricted cruise climb is 0.365, and the drag coefficient is 0.027. This gives the range function as 2566.033 which yields a range of 1337km
Variation of jet range with lift coefficient, airspeed¶
Recall that the lift coefficient is effectively a measure of the aircraft cruise speed. The range can be plotted vs. lift coefficient and forward speed for the two different cruise-climb cases over a range of starting altitudes.
Beware of source for the plots below…
Producing the plots below is fairly simple - but in order to get the labels and legend to work correctly, there’s a bit of obscure logic flow in the way the plot is created.
That is, it makes it look more complicated than it actually is (and it probably could be done better if I knew my way around plotly better).
import plotly.graph_objects as go
## Note that there's a lot of slightly peculiar logic in the code below that enables the annotation and the legend
# to to be printed. You don't need to worry about it.
# Define a range of Cls
CLrange = np.linspace(.1, 1.2, 1000)
# Drag is given from the drag model
CDrange = CD0 + K * CLrange**2
# The CL and CD for TRCC and TUCC are defined above, so they can be reused here
# Open three figures
fig = go.Figure()
fig2 = go.Figure()
fig3 = go.Figure()
# Make sigma function for convenience
def sigma_function(alt):
mosphere = Atmosphere(alt)
rho = mosphere.density[0]
sig = rho/rho_sl
return sig
# Iterate over altitudes
for i, h in enumerate(np.arange(4, 14, 2)*1e3):
# Get the density ratio
sig = sigma_function(h)
# Determine the cruise speed in TAS at this altitude
Vtas_knots = np.sqrt(Ws / (.5 * sig * rho_sl * S * CLrange)) /.5144444
Veas_knots = np.sqrt(Ws / (.5 * rho_sl * S * CLrange)) /.5144444
######## Thrust Restricted
# Get the range function (thrust restricted)
range_funct_trcc = np.sqrt(2 * T_sl / (rho_sl * S)) * CLrange / CDrange ** (3/2)
# Get the range for this altitude
R_trcc = 1 / f / g * range_funct_trcc * np.log(Ws/We) / 1e3
# Plot it
if i == 0:
fig.add_trace(go.Scatter(x=CLrange, y=R_trcc, mode="lines", name=f"Thrust-Restricted", line=dict(width=4,
dash='dash', color='red')))
fig2.add_trace(go.Scatter(x=Veas_knots, y=R_trcc, mode="lines", name=f"Thrust-Restricted", line=dict(width=4,
dash='dash', color='red')))
fig3.add_trace(go.Scatter(x=Vtas_knots, y=R_trcc, mode="lines", name=f"Thrust-Restricted", line=dict(width=4,
dash='dash', color='red')))
else:
fig.add_trace(go.Scatter(x=CLrange, y=R_trcc, mode="lines", name="DontPrint", line=dict(width=4,
dash='dash', color='red')))
fig2.add_trace(go.Scatter(x=Veas_knots, y=R_trcc, mode="lines", name="DontPrint", line=dict(width=4,
dash='dash', color='red')))
fig3.add_trace(go.Scatter(x=Vtas_knots, y=R_trcc, mode="lines", name="DontPrint", line=dict(width=4,
dash='dash', color='red')))
######## Thrust Unrestricted
# Get the range function (thrust unrestricted)
range_funct_tucc = np.sqrt(Ws / (0.5 * sig * rho_sl * S)) * CLrange ** .5 / CDrange
# Get the range for this altitude
R_tucc = 1 / f / g * range_funct_tucc * np.log(Ws/We) / 1e3
# Plot it
if i == 0:
fig.add_trace(go.Scatter(x=CLrange, y=R_tucc, mode="lines", name="Thrust-Unrestricted", line=dict(width=4, color='blue')))
fig2.add_trace(go.Scatter(x=Veas_knots, y=R_tucc, mode="lines", name="Thrust-Unrestricted", line=dict(width=4, color='blue')))
fig3.add_trace(go.Scatter(x=Vtas_knots, y=R_tucc, mode="lines", name="Thrust-Unrestricted", line=dict(width=4, color='blue')))
else:
fig.add_trace(go.Scatter(x=CLrange, y=R_tucc, mode="lines", name="DontPrint", line=dict(width=4, color='blue')))
fig2.add_trace(go.Scatter(x=Veas_knots, y=R_tucc, mode="lines", name="DontPrint", line=dict(width=4, color='blue')))
fig3.add_trace(go.Scatter(x=Vtas_knots, y=R_tucc, mode="lines", name="DontPrint", line=dict(width=4, color='blue')))
######## Label the altitudes:
if i == 0: fig.add_trace(go.Scatter(x=[CLrange[0]], y=[R_trcc[0]], mode="text", text="All altitudes", textposition="middle right", name="Annotation"))
fig.add_trace(go.Scatter(x=[CLrange[0]], y=[R_tucc[0]], mode="text", text=f"{h/1e3:1.0f}km", textposition="middle left", name="DontPrint"))
if i == 0: fig2.add_trace(go.Scatter(x=[Veas_knots[0]+16*i + 2], y=[R_trcc[0]], mode="text", text="All altitudes", textposition="middle right", name="Annotation"))
fig2.add_trace(go.Scatter(x=[Veas_knots[0]+2], y=[R_tucc[0]], mode="text", text=f"{h/1e3:1.0f}km", textposition="middle right", name="Annotation"))
fig3.add_trace(go.Scatter(x=[Vtas_knots[0]], y=[R_tucc[0]], mode="text", text=f"{h/1e3:1.0f}km", textposition="bottom center", name="Annotation"))
fig3.add_trace(go.Scatter(x=[Vtas_knots[0]], y=[R_trcc[0]], mode="text", text=f"{h/1e3:1.0f}km", textposition="bottom center", name="Annotation"))
# Determine the different Cls to plot for comparison
CL_trcc = np.sqrt(CD0/2/K)
CL_tucc = np.sqrt(CD0/3/K)
CL_md = np.sqrt(CD0/K)
CL_mp = np.sqrt(3*CD0/K)
# Overlay lines for different Cls on the first figure only
fig.add_trace(go.Scatter(x=[CL_trcc, CL_trcc], y=[400, 1500], name="DontPrint", mode="lines", line=dict(color="crimson")))
fig.add_trace(go.Scatter(x=[CL_tucc, CL_tucc], y=[400, 1500], name="DontPrint", mode="lines", line=dict(color="darkgreen")))
fig.add_trace(go.Scatter(x=[CL_md, CL_md], y=[400, 1500], name="DontPrint", mode="lines", line=dict(color="mediumpurple")))
fig.add_trace(go.Scatter(x=[CL_mp, CL_mp], y=[400, 1500], name="DontPrint", mode="lines", line=dict(color="gold")))
fig.add_trace(go.Scatter(x=[CL_trcc], y=[200], mode="text",\
text="$C_{L,trcc}=\sqrt{\\frac{C_{D0}}{2\,K}}$",\
textposition="bottom center", name="DontPrint",\
textfont=dict(color="crimson")))
fig.add_trace(go.Scatter(x=[CL_tucc], y=[300], mode="text",\
text="$C_{L,tucc}=\sqrt{\\frac{C_{D0}}{3\,K}}$",\
textposition="bottom center", name="DontPrint",\
textfont=dict(color="darkgreen")))
fig.add_trace(go.Scatter(x=[CL_md], y=[300], mode="text",\
text="$C_{L,md}=\sqrt{\\frac{C_{D0}}{K}}$",\
textposition="bottom center", name="DontPrint",\
textfont=dict(color="mediumpurple")))
fig.add_trace(go.Scatter(x=[CL_mp], y=[200], mode="text",\
text="$C_{L,mp}=\sqrt{\\frac{3\,C_{D0}}{2\,K}}$",\
textposition="bottom center", name="DontPrint",\
textfont=dict(color="gold")))
# Overlay lines for the EAS
def CLtoEAS(CL):
V = np.sqrt(Ws/(.5 * rho_sl * S * CL)) /.5144444
return V
fig2.add_trace(go.Scatter(x=[CLtoEAS(CL_trcc), CLtoEAS(CL_trcc)], y=[400, 1500], name="DontPrint", mode="lines", line=dict(color="crimson")))
fig2.add_trace(go.Scatter(x=[CLtoEAS(CL_tucc), CLtoEAS(CL_tucc)], y=[400, 1500], name="DontPrint", mode="lines", line=dict(color="darkgreen")))
fig2.add_trace(go.Scatter(x=[CLtoEAS(CL_md), CLtoEAS(CL_md)], y=[400, 1500], name="DontPrint", mode="lines", line=dict(color="mediumpurple")))
fig2.add_trace(go.Scatter(x=[CLtoEAS(CL_mp), CLtoEAS(CL_mp)], y=[400, 1500], name="DontPrint", mode="lines", line=dict(color="gold")))
fig2.add_trace(go.Scatter(x=[CLtoEAS(CL_trcc)], y=[200], mode="text",\
text="$V_{C_{L,trcc}}$",\
textposition="bottom center", name="DontPrint",\
textfont=dict(color="crimson")))
fig2.add_trace(go.Scatter(x=[CLtoEAS(CL_tucc)], y=[300], mode="text",\
text="$V_{C_{L,tucc}}$",\
textposition="bottom center", name="DontPrint",\
textfont=dict(color="darkgreen")))
fig2.add_trace(go.Scatter(x=[CLtoEAS(CL_md)], y=[300], mode="text",\
text="$V_{C_{L,md}}$",\
textposition="bottom center", name="DontPrint",\
textfont=dict(color="mediumpurple")))
fig2.add_trace(go.Scatter(x=[CLtoEAS(CL_mp)], y=[200], mode="text",\
text="$V_{C_{L,mp}}$",\
textposition="bottom center", name="DontPrint",\
textfont=dict(color="gold")))
# Remove junk legend entries - this would be more efficient if I weren't lazy
for trace in fig['data']:
if (trace['name'] == "DontPrint") or (trace['name'] == "Annotation"): trace['showlegend'] = False
for trace in fig2['data']:
if (trace['name'] == "DontPrint") or (trace['name'] == "Annotation"): trace['showlegend'] = False
for trace in fig3['data']:
if (trace['name'] == "DontPrint") or (trace['name'] == "Annotation"): trace['showlegend'] = False
fig.update_layout(
title="Thrust Restricted and Unrestricted Ranges vs. Lift Coefficient for different starting altitudes",
xaxis_title="$C_L$",
yaxis_title="Range/km",
)
fig2.update_layout(
title="Thrust Restricted and Unrestricted Ranges vs. EAS for different starting altitudes",
xaxis_title="$V_{E}/\\text{kn}$",
yaxis_title="Range/km",
)
fig3.update_layout(
title="Thrust Restricted and Unrestricted Ranges vs. TAS for different starting altitudes",
xaxis_title="$V/\\text{kn}$",
yaxis_title="Range/km",
)
# Figure 1
fig.update_xaxes(range=[0, 1.5])
fig.update_yaxes(range=[0, 1500])
fig2.update_yaxes(range=[0, 1500])
fig2.update_xaxes(range=[0, 500])
fig3.update_yaxes(range=[0, 1500])
fig.show()
fig2.show()
fig3.show()
Notice that the maximum range is found at a considerably higher speed than both the minimum power and minimum drag speeds, for both types of cruise climb. The ratio between the two speeds and the minimum drag speed may be readily shown.
These ratios hold across altitudes, as you should expect.
BRE - Propeller Aircraft¶
The BRE for propeller aircraft is similar to that for jet aircraft, but SFC is used in place of TSFC - the SI units are \(\text{kg}/{\text W s}\).
The BRE for propeller aircraft is
where \(P\) is the power delivered to the aircraft from the propeller. With \(\eta\) as the propeller efficiency, the power delivered is function of the power required
so the BRE becomes
Assuming, as for the jet cruise-climb case, that \(\tfrac{C_L}{C_D}\), \(f\), and \(V\) remain constant, the equation above can be integrated from \(W_S\) to \(W_E\) to yield the endurance, \(E\):
Propeller Aircraft: Maximum Endurance¶
Equation (10) shows that for the maximum endurance for a propeller-driven aircraft, the quanity \(\frac{C_L}{V\,C_D}\) must be maximised, which is different to the jet aircraft case.
Clearly the maximum endurance is found at the minimum power condition, thus for maximum endurance a propeller-driven aircraft should fly at \(V_{mp}\).
Propeller Aircraft: Maximum Range¶
The increment in aircraft distance, \(\text{d}S\) when flown at velocity \(V\) is given by
Clearly the maximum endurance is found at the minimum drag condition, thus for maximum endurance a propeller-driven aircraft should fly at \(V_{md}\).
Range and Endurance Summary¶
The maximum range for propeller-driven aircraft is the same as for a glider - consider that the maximum range is given by the least resistance encountered in the longitudinal direction, enabling the aircraft to fly furthest, so this is the minimum drag speed.
The maximum endurance for propeller-driven aircraft is the same as for a glider - this is determined by the speed at which the most work is done with the least energy (most bang for buck), so this is the minimum power speed.
These are relatively easy to intuit because in a glider, there is no input power - and for a propeller-driven aircraft, the propulsor is directly providing power.
For a jet-driven aircraft, the engine provides thrust, and hence the power varies with forward speed. To get maximum range, using a cruise-climb method, the problem must be constrained somehow:
If the thrust is held constant, and altitude allowed to vary then the best \(C_L\) is \(\sqrt{\frac{C_{D0}}{2\,K}}\)
If the thrust is allowed to vary to maintain \(C_L\), then the best \(C_L\) is \(\sqrt{\frac{C_{D0}}{3\,K}}\)
The best range is found using the second method, starting at a greater altitude.
The starting altitude does not affect the range using the first method.
| Glider | Jet Aircraft | Propeller Aircraft | |
|---|---|---|---|
| Maximum Endurance | At $V_{mp}$ | At $V_{md}$ | At $V_{mp}$ |
| Maximum Range | At $V_{md}$ | $\gt V_{md}$ | At $V_{md}$ |
All of the cruise-climb scenarios are theoretical behaviour, and are reliant on the assumptions made within these models - furthermore, cruise-climb is typically not allowed by ATC. Rather, a series of stepped-climbs are made.
Nonetheless, the methods shown here allow a good estimate of range to be made - and afford the ability to look at the effect of design parameters on range and endurance.


